using System;
using System.Collections.Generic;
using System.Text;
using GameStateManager;
using System.Threading;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using ScreenTest.Players;
using ScreenTest.Projectiles;
using ScreenTest.World;
using ScreenTest.Constants;

namespace ScreenTest.Screens
{
    class GamePlayScreen : GameScreen
    {
        ContentManager content;
        Texture2D image;
        Texture2D regularProjectileTexture;
        Texture2D rocketTexture;
        SpriteFont spriteFont;
        Texture2D playerOneTexture;
        Texture2D playerTwoTexture;
        SpriteFont scoreFont;

        Vector2 textPosition;
        Random rnd = new Random();
        Level level;

        List<Projectile> projectiles;

        Player player1;
        Player player2;

        Hud player1Hud;
        Hud player2Hud;

        bool levelOver;
        int levelWinner;
        bool quitGame;

        public GamePlayScreen()
        {
            projectiles = new List<Projectile>();
            player1 = new Player(0, this, new Vector2(100, 100), -1);
            player2 = new Player(1, this, new Vector2(100, 100), -1);
            levelOver = false;
            levelWinner = 0;
            quitGame = false;
        }

        public override void LoadGraphicsContent(bool loadAllContent)
        {
            if (content == null)
            {
                content = new ContentManager(ScreenManager.Game.Services);
                image = content.Load<Texture2D>(@"Content\test");
                spriteFont = content.Load<SpriteFont>(@"Fonts\LoadingFont");
                regularProjectileTexture = content.Load<Texture2D>(@"Content\base_regular_projectile");
                playerOneTexture = content.Load<Texture2D>(@"Content\blue_tank");
                playerTwoTexture = content.Load<Texture2D>(@"Content\red_tank");
                scoreFont = content.Load<SpriteFont>(@"Fonts\Score");
                rocketTexture = content.Load<Texture2D>(@"Content\rocket");

                player1Hud = new Hud(player1, content);
                player2Hud = new Hud(player2, content);
            }

            level = new Level();
            level.Load(content, @"Levels\level1.dat");
            player1.Respawn(level.Player1Spawn);
            player2.Respawn(level.Player2Spawn);
        }

        public override void HandleInput(InputState inputState, GameTime gameTime)
        {
            bool pause = false;
            PauseScreen pauseScreen = null;

            if (inputState.StartIsPressed(0))
            {
                //Player 1 has pasued the game
                pauseScreen = new PauseScreen(0);
                pause = true;
            }
            else if (inputState.StartIsPressed(1))
            {
                //Player 2 has pasued the game
                pauseScreen = new PauseScreen(1);
                pause = true;

            }
            else
            {
                player1.HandleInput(inputState, gameTime);
                player2.HandleInput(inputState, gameTime);
            }

            if (pause)
            {
                pauseScreen.userResponse += this.ReactToPauseScreen;
                ScreenManager.AddScreen(pauseScreen);
            }
        }

        public override void UnLoadGraphicsContent(bool unloadAllContent)
        {
            content.Unload();
        }

        public override void Update(GameTime gameTime, bool otherScreenHasFocus)
        {
            if (!otherScreenHasFocus)
            {
                if (levelOver)
                {
                    //This statement is only reached when a player has
                    //died and the winner presentation screen is removed.
                    GameReset();
                }

                UpdateGameLogic(gameTime);

                if (quitGame)
                {
                    ScreenManager.RemoveScreen(this);
                    ScreenManager.Game.Exit();
                }
            }
        }

        public override void Draw(GameTime gameTime)
        {
            Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
            Rectangle fullscreen = new Rectangle(0, 0, viewport.Width, viewport.Height);

            ScreenManager.GraphicsDevice.Clear(Color.Black);

            level.Draw(ScreenManager.GraphicsDevice, ScreenManager.SpriteBatch);

            ScreenManager.SpriteBatch.Begin();
            ScreenManager.SpriteBatch.Draw(playerOneTexture, new Rectangle((int)player1.Position.X, (int)player1.Position.Y, 64, 64), null, Color.White);
            ScreenManager.SpriteBatch.Draw(playerTwoTexture, new Rectangle((int)player2.Position.X, (int)player2.Position.Y, 64, 64), null, Color.White);

            foreach (Projectile projectile in projectiles)
            {
                Vector2 center;
                Texture2D texture;

                if (projectile.Type == GameConstants.PROJECTILE_NORMAL)
                {
                    texture = regularProjectileTexture;
                    center = new Vector2(4, 4);
                }
                else
                {
                    texture = rocketTexture;
                    center = new Vector2(rocketTexture.Width / 2, rocketTexture.Height / 2);
                }
                float angle = (float)(Math.Atan2(projectile.velocity.Y, projectile.velocity.X) - Math.Atan2(0, 1));
                ScreenManager.SpriteBatch.Draw(texture, new Rectangle((int)projectile.position.X, (int)projectile.position.Y, 8, 8), null, Color.White, angle, center, SpriteEffects.None, 0f);
                //ScreenManager.SpriteBatch.Draw(texture, new Rectangle((int)projectile.position.X, (int)projectile.position.Y, 8, 8), null, Color.White, angle, Vector2.Zero, SpriteEffects.None, 0f);
            }

            DrawPlayerScores();
            player1Hud.Draw(ScreenManager.GraphicsDevice, ScreenManager.SpriteBatch);
            player2Hud.Draw(ScreenManager.GraphicsDevice, ScreenManager.SpriteBatch);
            ScreenManager.SpriteBatch.End();

            
        }

        /// <summary>
        /// Draw the players scores in the corner
        /// </summary>
        void DrawPlayerScores()
        {
            Rectangle safeArea = ScreenManager.GetTitleSafeArea();

            //Our strings
            String player1Score = "Player 1: " + player1.Score.ToString();
            String player1Health = "Health: " + player1.Health.ToString();
            String player2Score = "Player 2: " + player2.Score.ToString();
            String player2Health = "Health: " + player2.Health.ToString();

            Vector2 lineHeightOffset = new Vector2(0,scoreFont.LineSpacing + 2);
            Vector2 player2ScoreLineSize = scoreFont.MeasureString(player2Score);
            Vector2 player2HealthLineSize = scoreFont.MeasureString(player2Health);

            Vector2 player1Start = new Vector2(safeArea.X, safeArea.Y);

            Vector2 player2ScoreStart = new Vector2(safeArea.Width - player2ScoreLineSize.X, safeArea.Y);
            Vector2 player2HealthStart = new Vector2(safeArea.Width - player2HealthLineSize.X, safeArea.Y + scoreFont.LineSpacing + 2);

            ScreenManager.SpriteBatch.DrawString(scoreFont, player1Score, player1Start, Color.White);
            ScreenManager.SpriteBatch.DrawString(scoreFont, player1Health, player1Start + lineHeightOffset, Color.White);

            ScreenManager.SpriteBatch.DrawString(scoreFont, player2Score, player2ScoreStart, Color.White);
            ScreenManager.SpriteBatch.DrawString(scoreFont, player2Health, player2HealthStart, Color.White);

        }

        /// <summary>
        /// Cause a reset of the game
        /// </summary>
        void GameReset()
        {
            level.Reset();
            projectiles.Clear();
            BoardRest();
            levelOver = false;
            levelWinner = 0;
        }

        /// <summary>
        /// Updates the games logic which is only run if this screen
        /// has the focus.
        /// </summary>
        /// <param name="gameTime"></param>
        void UpdateGameLogic(GameTime gameTime)
        {
            TestProjectilesAgainstWorld();
            TestPlayersAgainstWorld();
            TestProjectilesAgainstPlayer();

            level.Update(gameTime);

            foreach (Projectile projectile in projectiles)
            {
                projectile.position += projectile.velocity;
            }

            player1.Update();
            player2.Update();

            player1Hud.Update(gameTime);
            player2Hud.Update(gameTime);

            TestPlayerAliveness();

            if (levelOver)
            {
                PlayerWonScreen playerWonScreen = new PlayerWonScreen(levelWinner);
                playerWonScreen.StarTimer();
                ScreenManager.AddScreen(playerWonScreen);
            }
        }

        /// <summary>
        /// Test for player Aliveness
        /// </summary>
        void TestPlayerAliveness()
        {
            bool someoneDied = false;

            if (!player1.IsAlive)
            {
                someoneDied = true;
                levelWinner = 2;
            }
            else if (!player2.IsAlive)
            {
                someoneDied = true;
                levelWinner = 1;
            }

            if (someoneDied)
            {
                levelOver = true;
                

            }
        }

        /// <summary>
        /// Resets the players back to their spawning positions
        /// </summary>
        void BoardRest()
        {
            player1.Respawn(level.Player1Spawn);
            player2.Respawn(level.Player2Spawn);
        }

        /// <summary>
        /// Performs collision of projetiles against the world
        /// </summary>
        void TestProjectilesAgainstWorld()
        {
            Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
            List<Projectile> removals = new List<Projectile>();

            for (int i = 0; i < projectiles.Count; i++)
            {
                Projectile projectile = projectiles[i];
                Vector2 position = projectile.position;

                if (position.X < 0)
                {
                    projectile.velocity.X *= -1f;
                }
                else if (position.X > viewport.Width)
                {
                    projectile.velocity.X *= -1f;
                }

                if (position.Y < 0 || position.Y > viewport.Height)
                {
                    projectile.velocity.Y *= -1f;
                }

                //construct projectile bbox
                BoundingBox pBox = new BoundingBox();
                pBox.Min = new Vector3(position.X - 4, position.Y - 4, 0);
                pBox.Max = new Vector3(position.X + 4, position.Y + 4, 0);

                if (level.Collides(pBox))
                {
                    removals.Add(projectile);
                }
            }

            foreach (Projectile p in removals)
            {
                projectiles.Remove(p);
            }
        }

        /// <summary>
        /// Tests to see if either player has been hit by an enemy
        /// projectile.
        /// </summary>
        void TestProjectilesAgainstPlayer()
        {
            List<Projectile> removals = new List<Projectile>();

            for (int i = 0; i < projectiles.Count; i++)
            {
                Projectile projectile = projectiles[i];

                if (projectile.GetBoundingBox().Intersects(player1.GetBoundingBox()))
                {
                    if (projectile.owner != player1.ID)
                    {
                        player1.HitByProjectile(projectile);
                        player2.RecordHit();
                        removals.Add(projectile);
                        //score a hit with the player
                    }
                }
                else if (projectile.GetBoundingBox().Intersects(player2.GetBoundingBox()))
                {
                    if (projectile.owner != player2.ID)
                    {
                        player2.HitByProjectile(projectile);
                        player1.RecordHit();
                        removals.Add(projectile);
                    }
                }
            }

            foreach (Projectile p in removals)
            {
                projectiles.Remove(p);
            }
        }

        /// <summary>
        /// Tests each players movements against the world.
        /// </summary>
        void TestPlayersAgainstWorld()
        {
            level.CheckPlayerAgainstWorld(player1);
            level.CheckPlayerAgainstWorld(player2);
            level.PlayerTouchesItems(player1);
            level.PlayerTouchesItems(player2);
        }

        /// <summary>
        /// Fires a regular projectile
        /// </summary>
        /// <param name="playerID">Owner of this projectile</param>
        /// <param name="position">Starting position</param>
        /// <param name="direction">Direction of travel</param>
        /// <param name="speed">Speed of travel</param>
        public void FireRegularWeapon(int playerID, Vector2 position, Vector2 direction, float speed)
        {
            Vector2 velocity = direction;
            velocity.Normalize();
            velocity *= speed;

            Projectile projectile = new Projectile(GameConstants.PROJECTILE_NORMAL);
            projectile.position = position;
            projectile.velocity = velocity;
            projectile.owner = playerID;

            projectiles.Add(projectile);
        }

        /// <summary>
        /// Fires a rocket projectile
        /// </summary>
        /// <param name="playerID">Owner of the projectile</param>
        /// <param name="position">Starting position</param>
        /// <param name="direction">Direction of travel</param>
        /// <param name="speed">Speed of travel</param>
        public void FireRocket(int playerID, Vector2 position, Vector2 direction, float speed)
        {
            Vector2 velocity = direction;
            velocity.Normalize();
            velocity *= speed;

            Projectile projectile = new Projectile(GameConstants.PROJECTILE_ROCKET);
            projectile.position = position;
            projectile.velocity = velocity;
            projectile.owner = playerID;

            projectiles.Add(projectile);
        }

        void LoadNextLevel(String level)
        {
        }

        void ReactToPauseScreen(int result)
        {
            if (result == PauseConstants.PAUSE_QUIT)
                quitGame = true;
        }
    }
}
